﻿#region

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using Tateeda.ClinicalStudy.Base.Data.DBModel;
using Tateeda.ClinicalStudy.Base.Data.EF;
using Tateeda.ClinicalStudy.Base.Modules.Common;
using Tateeda.ClinicalStudy.Base.Modules.Common.Enumeration;
using Tateeda.ClinicalStudy.Base.Modules.Common.Extenstions;
using Tateeda.ClinicalStudy.Base.Modules.Infrastructure.Interfaces.Services;
using Tateeda.ClinicalStudy.Base.Modules.Models.StudyForm;
using Tateeda.ClinicalStudy.Base.Modules.Models.StudyVisit;

#endregion

#region - Legal -

///<legal>
/// Copyright © 2011, Tateeda Media Network
/// All rights reserved. http://tateeda.com
///
/// Redistribution and use in source and binary forms, with or without
/// modification, are permitted provided that the following conditions
/// are met:
///
/// - Redistributions of source code must retain the above copyright
/// notice, this list of conditions and the following disclaimer.
///
/// - Neither the name of the Tateeda Media Network, nor the names of its
/// contributors may be used to endorse or promote products
/// derived from this software without specific prior written
/// permission.
///
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
/// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
/// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
/// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
/// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING,
/// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
/// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
/// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
/// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
/// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
/// POSSIBILITY OF SUCH DAMAGE.
///</legal>

#endregion - Legal -

namespace Tateeda.ClinicalStudy.Base.Modules.Infrastructure.Concrete.Services {

    public class MatrixService : IMatrixService {
        private readonly IAppointmentService _appointmentService = new AppointmentService();
        private readonly IFormService _formService = new FormService();
        private readonly SqlUnitOfWork _unitOfWork;

        public MatrixService() {
            _unitOfWork = new SqlUnitOfWork();
        }

        #region IMatrixService Members

        public virtual IUnitOfWork UnitOfWork {
            get { return _unitOfWork; }
        }

        public virtual string MatrixMappingHTML() {
            return GetMatrixMappingHTML();
        }

        public virtual void CreateVisitToFormMap(int visitId, int[] formIdArray) {
            // make sure visit exists
            // first delete all existing map records
            IQueryable<VisitForm> del = UnitOfWork.VisitForms
                .Where(vf => vf.VisitId == visitId);

            foreach (VisitForm d in del) {
                UnitOfWork.VisitForms.DeleteObject(d);
            }

            // reinsert map records
            foreach (int formId in formIdArray) {
                var vf = new VisitForm {
                    VisitId = visitId,
                    FormId = formId
                };
                UnitOfWork.VisitForms.AddObject(vf);
            }

            UnitOfWork.Commit();
        }

        public virtual void CreateVisit(VisitModel visit) {
            UnitOfWork.Visits.AddObject(visit.ToVisit());
            UnitOfWork.Commit();
        }

        public virtual ICollection<StudyFormModel> GetActiveForms(StudyFormType formType) {
            return _formService.GetForms(StudyStatus.ActiveStatus, formType);
        }

        public virtual VisitModel GetVisit(int visitId) {
            return UnitOfWork.Visits.Where(v => v.VisitId == visitId).Single().ToVisitModel();
        }

        public virtual ICollection<StudyFormModel> GetVisitMappedForms(int visitId, StudyFormType formType) {
            ICollection<StudyFormModel> forms = _appointmentService.GetFormsForVisit(visitId, formType);
            return forms;
        }

        public ICollection<VisitModel> GetVisits() {
            return UnitOfWork.Visits.Include("VisitType").Include("Arm").ToList().ToVisitModelList();
        }

        public void UpdateVisit(VisitModel visitModel) {
            Visit editVisit = UnitOfWork.Visits.Where(v => v.VisitId == visitModel.VisitId).Single();
            Util.CopyFromModel(visitModel, ref editVisit);
            editVisit.UpdatedOn = DateTime.UtcNow;

            UnitOfWork.Commit();
        }

        public void UpdateVisitFormsOrder(int visitId, Dictionary<int, int> formsId) {
            IQueryable<VisitForm> visits = UnitOfWork.VisitForms.Where(vf => vf.VisitId == visitId);
            foreach (VisitForm vis in visits) {
                VisitForm vis1 = vis;
                VisitForm item =
                    UnitOfWork.VisitForms.Where(v => vis1 != null && (v.VisitId == visitId && v.FormId == vis1.FormId)).
                        Single();
                item.SortOrder = formsId[vis.FormId];
            }
            UnitOfWork.Commit();
        }

        public void DeleteVisit(int visitId) {
            Visit visit = UnitOfWork.Visits.Where(v => v.VisitId == visitId).Single();
            UnitOfWork.Visits.DeleteObject(visit);
            UnitOfWork.Commit();
        }

        #endregion

        #region - Private Methods -

        private string GetMatrixMappingHTML() {
            var sb = new StringBuilder();
            const string x = "<b>X</b>";
            const string space = "&nbsp;";

            ICollection<StudyFormModel> forms = _formService.GetForms(StudyStatus.ActiveStatus, StudyFormType.DynamicForm);
            ICollection<StudyFormModel> labs = _formService.GetForms(StudyStatus.ActiveStatus, StudyFormType.DynamicLab);
            ICollection<VisitModel> visits = _appointmentService.GetVisits(StudyStatus.ActiveStatus);

            int visCnt = visits.Count;

            sb.Append(
                @"
                <div class='matrixViewDiv'>
				<table class='matrixViewTable'>
					<tr valign='top'><th style='align:left; width:75px;'>Visits<br/><hr style='width:75px; align:left;'/>Forms/Labs</th>");

            foreach (VisitModel v in visits) {
                sb.AppendFormat("<th>{0}</th>", v.Name);
            }
            sb.Append("</tr>");

            sb.AppendFormat("<tr valign='top'><td>Forms:</td><td colspan='{0}'>{1}</td></tr>", visCnt, space);

            //Mark matching Forms
            foreach (StudyFormModel f in forms) {
                var formVisits = _appointmentService.GetVisitsForForm(f.FormId);
                sb.AppendFormat("<tr valign='top'><th nowrap='nowrap'>{0}</th>", f.Name);

                if (formVisits.Count > 0) {
                    foreach (VisitModel v in visits) {
                        VisitModel yes = formVisits.ToList().Find(n => n.VisitId == v.VisitId);

                        if (yes != null) {
                            sb.AppendFormat("<td>{0}</td>", x);
                        } else {
                            sb.AppendFormat("<td >{0}</td>", space);
                        }
                    }
                } else {
                    foreach (VisitModel t in visits) {
                        sb.AppendFormat("<td>{0}</td>", space);
                    }
                }
                sb.Append("</tr>");
            }

            sb.AppendFormat("<tr valign='top'><td>Labs:</td><td colspan='{0}'>{1}</td></tr>", visCnt, space);
            //Mark matching Labs
            foreach (StudyFormModel l in labs) {
                ICollection<VisitModel> labVisits = _appointmentService.GetVisitsForForm(l.FormId);
                sb.AppendFormat("<tr valign='top'><th>{0}</th>", l.Name);

                if (labVisits.Count > 0) {
                    foreach (VisitModel v in visits) {
                        VisitModel y = labVisits.ToList().Find(lv => lv.VisitId == v.VisitId);

                        if (y != null) {
                            sb.AppendFormat("<td>{0}</td>", x);
                        } else {
                            sb.AppendFormat("<td >{0}</td>", space);
                        }
                    }
                } else {
                    foreach (VisitModel t in visits) {
                        sb.AppendFormat("<td >{0}</td>", space);
                    }
                }
                sb.Append("</tr>");
            }
            sb.Append("</table>");
            return sb.ToString();
        }

        #endregion - Private Methods -
    }
}